package com.ynet.middleground.oss.utils;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import org.dozer.Mapper;
import org.springframework.beans.BeanUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Throwables;
import com.ynet.core.common.BaseReqObj;
import com.ynet.core.log.IfpLogger;

/**
 * @author liulx
 * @description 对象处理工具类
 * @date 2019-10-11 16:46
 */
public class BeanUtil {

    /***
     * 转化显示Bean
     *
     * @param list 待转化列表
     * @param clazz 目标类
     * @param <T>
     * @return 转化后的List
     * @throws Exception
     */
    public static <T> List<T> listToBeanVo(List list, Class<T> clazz, String... ignoreProperties) throws Exception {
        List<T> resultList = new ArrayList<>();
        if (list == null) {
            return resultList;
        }

        for (Object obj : list) {
            T t = objToBeanVo(obj, clazz, ignoreProperties);
            resultList.add(t);
        }

        return resultList;
    }

    /**
     * 复制源对象属性到目标对象
     *
     * @param obj 源对象
     * @param clazz 目标类型
     * @param ignoreProperties 需忽略属性列表
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T objToBeanVo(Object obj, Class<T> clazz, String... ignoreProperties) throws Exception {
        T t = (T)Class.forName(clazz.getName()).newInstance();
        BeanUtils.copyProperties(obj, t, ignoreProperties);
        return t;
    }

    /**
     * 封装dozer处理集合的方法：List<S> --> List<T>
     */
    public static <T, S> List<T> mapList(Mapper mapper, List<S> sourceList, Class<T> targetObjectClass) {
        if (sourceList == null) {
            return Collections.EMPTY_LIST;
        }
        return sourceList.stream().map(s -> mapper.map(s, targetObjectClass)).collect(Collectors.toList());
    }

    /**
     * 找出 List 重复的元素
     * 
     * @param list 原集合列表
     * @param <E> 集合中的类型
     * @return 重复的元素列表
     */
    public static <E> List<E> getDuplicateElements(List<E> list) {
        if (list == null) {
            return Collections.EMPTY_LIST;
        }
        return list.stream()
            // 获得元素出现频率的 Map，键为元素，值为元素出现的次数
            .collect(Collectors.toMap(e -> e, e -> 1, Integer::sum))
            // 所有 entry 对应的 Stream
            .entrySet().stream()
            // 过滤出元素出现次数大于 1 (重复元素）的 entry
            .filter(e -> e.getValue() > 1)
            // 获得 entry 的键（重复元素）对应的 Stream
            .map(Map.Entry::getKey)
            // 转化为 List
            .collect(Collectors.toList());
    }

    /**
     * 给对象设置通用属性值，channel、gmtCreate、createBy、gmtModified、modifiedBy
     * 
     * @param t 数据库对应 POJO 对象
     * @param req 基础请求类
     * @param <T>
     * @return 设置值后的对象
     */
    public static <T> T setGenericInfo(T t, BaseReqObj req) {
        try {
            Class<?> clazz = t.getClass();
            Field field = clazz.getDeclaredField("channel");
            field.setAccessible(true);
            field.set(t, req.getChannel());

            field = clazz.getDeclaredField("gmtCreate");
            field.setAccessible(true);
            field.set(t, LocalDateTime.now());

            field = clazz.getDeclaredField("createBy");
            field.setAccessible(true);
            field.set(t, req.getOperationUserId());

            field = clazz.getDeclaredField("gmtModified");
            field.setAccessible(true);
            field.set(t, LocalDateTime.now());

            field = clazz.getDeclaredField("modifiedBy");
            field.setAccessible(true);
            field.set(t, req.getOperationUserId());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "设置对象共有属性异常, case: {}",
                Throwables.getStackTraceAsString(e));
        }
        return t;
    }

    /**
     *
     * 对json数据key进行替换
     * 
     * @author songyf
     * @date 2020-08-07
     *
     */
    public static JSONObject changeJsonObj(JSONObject jsonObj, Map<String, String> keyMap) {
        JSONObject resJson = new JSONObject();
        Set<String> keySet = jsonObj.keySet();
        for (String key : keySet) {
            String resKey = keyMap.get(key) == null ? key : keyMap.get(key);
            try {
                JSONObject jsonobj1 = jsonObj.getJSONObject(key);
                resJson.put(resKey, changeJsonObj(jsonobj1, keyMap));
            } catch (Exception e) {
                try {
                    JSONArray jsonArr = jsonObj.getJSONArray(key);
                    resJson.put(resKey, changeJsonArr(jsonArr, keyMap));
                } catch (Exception x) {
                    resJson.put(resKey, jsonObj.get(key));
                }
            }
        }
        return resJson;
    }

    public static JSONArray changeJsonArr(JSONArray jsonArr, Map<String, String> keyMap) {
        JSONArray resJson = new JSONArray();
        for (int i = 0; i < jsonArr.size(); i++) {
            JSONObject jsonObj = jsonArr.getJSONObject(i);
            resJson.add(changeJsonObj(jsonObj, keyMap));
        }
        return resJson;
    }
}
